In Python, how do I get a function's name as a string?
I want to get the name of the str.capitalize() function as a string. It appears that the function has a __name__ attribute. When I do
print str.__name__
I get this output, as expected:
str
But when I run str.capitalize().__name__ I get an error instead of getting the name "capitalize".
> Traceback (most recent call last):
> File "string_func.py", line 02, in <module>
> print str.capitalize().__name__
> TypeError: descriptor 'capitalize' of 'str' object needs an argument
Similarly,
greeting = 'hello, world'
print greeting.capitalize().__name__
gives this error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'str' object has no attribute '__name__'
What went wrong?
greeting.capitalize is a function object, and that object has a .__name__ attribute that you can access. But greeting.capitalize() calls the function object and returns the capitalized version of the greeting string, and that string object doesn't have a .__name__ attribute. (But even if it did have a .__name__, it'd be the name of the string, not the name of the function used to create the string). And you can't do str.capitalize() because when you call the "raw" str.capitalize function you need to pass it a string argument that it can capitalize.
So you need to do
print str.capitalize.__name__
or
print greeting.capitalize.__name__
Let's start from the error
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'str' object has no attribute 'name'
Specific
AttributeError: 'str' object has no attribute 'name'
You are trying
greeting = 'hello, world'
print greeting.capitalize().__name__
Which will capitalize hello world and return it as a string.
As the error states, string don't have attribute _name_
capitalize() will execute the function immediately and use the result whereas capitalize will represent the function.
If you want to see a workaround in JavaScript,
Check the below snippet
function abc(){
return "hello world";
}
console.log(typeof abc); //function
console.log(typeof abc());
So, don't execute.
Simply use
greeting = 'hello, world'
print greeting.capitalize.__name__
You don't need to call this function and simply use name
>>> str.capitalize.__name__
Related
I'm trying to find an example of something in Python that can't be cast to a string.
>>> str(None)
'None'
>>> str(False)
'False'
>>> str(5)
'5'
>>> str(object)
"<class 'object'>"
>>> class Test:
... pass
...
>>> str(Test)
"<class '__main__.Test'>"
>>> str(Test())
'<__main__.Test object at 0x7f7e88a13630>'
Is there anything the entire Python universe that cannot be cast to str?
From the __str__ documentation:
The default implementation defined by the built-in type object
calls object.__repr__().
and object.__repr__ prints object name and address (at least in cpython). That's where your output '<__main__.Test object at 0x7f7e88a13630>' comes from. A class would have to override __str__ and raise an exception (or have a bug) to fail. There is little reason to do this and you'd be hard-pressed to find one that wasn't built to purpose.
Is everything in Python castable to a string?
Nope!
>>> class MyObject():
... def __str__(self):
... raise NotImplementedError("You can't string me!")
...
>>> str(MyObject())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in __str__
NotImplementedError: You can't string me!
I have a dictionary which is output of an aerospike info command. I need to parse a value from it.
I have set it as a string to the response variable as shown below. However, it's type still shows as dictionary. So, as suggested in this answer, I have dumped it to string type and then tried to call match() (because it expects string parameter). However, I am still getting this error.
respone = "{'BB912E94CDE0B0E': (None, 'n_objects=179:n-bytes-memory=0:stop-writes-count=0:set-enable-xdr=use-default:disable-eviction=true:set-delete=false;\n')}"
p = "/.*\'n_objects=([0-9]+)\:.*/gm"
stringResponse = json.dumps(response)
print type(response)
print stringResponse
print type(stringResponse)
print re.match(p,stringResponse).group(1)
Output -
<type 'dict'>
{"BB912E94CDE0B0E": [null, "n_objects=179:n-bytes-memory=0:stop-writes-count=0:set-enable-xdr=use-default:disable-eviction=true:set-delete=false;\n"]}
<type 'str'>
Traceback (most recent call last):
File "Sandeepan-oauth_token_cache_complete_sanity_cp.py", line 104, in <module>
print re.match(p,stringResponse).group(1)
AttributeError: 'NoneType' object has no attribute 'group'
I am getting the desired output using the same string and regex pattern - https://regex101.com/r/ymotqe/1
You need to correct your pattern. The /gm part at the end corresponds to flags for regex. Some other things '/' are also not needed.
import json
import re
# fixed variable name
response = "{'BB912E94CDE0B0E': (None, 'n_objects=179:n-bytes-memory=0:stop-writes-count=0:set-enable-xdr=use-default:disable-eviction=true:set-delete=false;\n')}"
# fixed pattern
p = ".*'n_objects=([0-9]+):.*"
stringResponse = json.dumps(response)
print stringResponse
print type(response)
# fixed flags parameter (but you do not need it in your example)
print re.match(p,stringResponse, flags=re.M).group(1)
Output:
"{'BB912E94CDE0B0E': (None, 'n_objects=179:n-bytes-memory=0:stop-writes-count=0:set-enable-xdr=use-default:disable-eviction=true:set-delete=false;\n')}"
<type 'str'>
179
When using regex101.com you should also switch to python mode.
I would like to implement a deferred exception in Python that is OK to store somewhere but as soon as it is used in any way, it raises the exception that was deferred. Something like this:
# this doesn't work but it's a start
class DeferredException(object):
def __init__(self, exc):
self.exc = exc
def __getattr__(self, key):
raise self.exc
# example:
mydict = {'foo': 3}
try:
myval = obtain_some_number()
except Exception as e:
myval = DeferredException(e)
mydict['myval'] = myval
def plus_two(x):
print x+2
# later on...
plus_two(mydict['foo']) # prints 5
we_dont_use_this_val = mydict['myval'] # Always ok to store this value if not used
plus_two(mydict['myval']) # If obtain_some_number() failed earlier,
# re-raises the exception, otherwise prints the value + 2.
The use case is that I want to write code to analyze some values from incoming data; if this code fails but the results are never used, I want it to fail quietly; if it fails but the results are used later, then I'd like the failure to propagate.
Any suggestions on how to do this? If I use my DeferredException class I get this result:
>>> ke = KeyError('something')
>>> de = DeferredException(ke)
>>> de.bang # yay, this works
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in __getattr__
KeyError: 'something'
>>> de+2 # boo, this doesn't
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'DeferredException' and 'int'
Read section 3.4.12 of the docs, "Special method lookup for new-style classes." It explains exactly the problem you have encountered. The normal attribute lookup is bypassed by the interpreter for certain operators, such as addition (as you found out the hard way). Thus the statement de+2 in your code never calls your getattr function.
The only solution, according to that section, is to insure that "the special method must be set on the class object itself in order to be consistently invoked by the interpreter."
Perhaps you'd be better off storing all your deferred exceptions in a global list, wrapping your entire program in a try:finally: statement, and printing out the whole list in the finally block.
For instance, if I have a call to the split method (i.e. some_string.split(":") )
Is is possible to mock this. I wanted to assert that the split function is called using assert_called_once_with
I confirm you can't do that because split() is a built-in attribute of str object and you can't set attributes of built-in or extension because they are readonly.
Below some inconclusive tests after trying into a Python 2.7.10 interpreter
>>> __builtins__.str.split
<method 'split' of 'str' objects>
>>> type(__builtins__.str.split)
<type 'method_descriptor'>
Trying to override it using a function
>>> type(lambda f:f)
<type 'function'>
>>> __builtins__.str.split = lambda f: f
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'str'
Trying to override it using a callable (function or method)
>>> type(callable)
<type 'builtin_function_or_method'>
>>> __builtins__.str.split = callable
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'str'
After having a look more deeply into the CPython source code here [1]. It's a limitation in Objects/typeobject.c introduce by the function list below. This function check if we try to set a readonly attribute and raise TypeError.
type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
{
if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
PyErr_Format(
PyExc_TypeError,
"can't set attributes of built-in/extension type '%s'",
type->tp_name);
return -1;
}
if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0)
return -1;
return update_slot(type, name);
}
[1] https://hg.python.org/cpython/file/tip/Objects/typeobject.c#l3022
Yes it is with a couple of caviats.
In my case I have successfully mocked str in python3 so I can assert that split is being called with a specific input
There are two caviats
With patch, I replaced the original str class with a new class that inherits from str
In the code that I was testing, I had to do a redundant string casting like str(str_val).split
Here's how one can do it:
class MyStr(str):
def split(self, sep=None, maxsplit=-1)):
expected_str = "some_input_mutated_inside_fn_before_split_called"
self.assertEqual(self, expected_str)
return super().split(sep=sep, maxsplit=maxsplit)
with patch('mymodule.str', new=MyStr):
output = mymodule.function_that_calls_string_split(
"some_input"
)
I am trying to join 2 strings using this code:
def __get_temp(self):
return float(self.ask('RS'))
def __set_temp(self, temp):
set = ('SS' + repr(temp))
stat = self.ask(set)
return self.check(stat)
temp = property(__get_temp, __set_temp)
Once together, I then send a signal over a serial bus using PyVisa. However, when I try to call the function, I get
Traceback (most recent call last):
File "<pyshell#4>", line 1, in <module>
chil.temp(13)
TypeError: 'float' object is not callable
I've tried looking around for explanation of this error, but none of them make any sense. Anyone know what is going on?
It looks like you are trying to set the property temp, but what you're actually doing is getting the property and then trying to call it as function with the parameter 13. The syntax for setting is:
chil.temp = 13