Is this possible in Python?
class MyClass(object):
#property
def property(self):
return self._property
That is, I want to have a property named 'property'. It actually runs fine, but Eclipse complains with a warning. I thought the built-in #property decorator lived in a different namespace than the methods and properties within my classes.
Is it possible to rename the built-in decorator within the scope of the relevant module, so I can use the name 'property' without receiving this warning? Maybe something like the following:
attr = property
class MyClass(object):
#attr
def property(self):
return self._property
I do this, but I still get the warning, since I created an alias for the global built-in #property decorator, but the name 'property' is still a valid way to refer to it.
Any ideas?
The problem with naming a property property is the following:
class Foo(object):
#property
def property(self):
return "ham"
#property
def other_property(self):
return "spam"
The second property can't be defined since you've shadowed the name property in the class definition.
You can get around this by "renaming" property as in your example, but if I were you, I wouldn't mess with the built-ins in this way. It makes your code harder to follow.
Decorators are ordinary functions, so they live in the same namespace as other functions. Indeed your property function is inside class Foo; but it turns out that that's where python first looks for decorator names, so there's a conflict.
You can see this from the fact that the following code compiles:
class Foo(object):
def decfun(x): return "ham"
#decfun
def second(self, y): pass
Related
I've got some code where I need to refer to a superclass when defining stuff in a derived class:
class Base:
def foo(self):
print('foo')
def bar(self):
print('bar')
class Derived_A(Base):
meth = Base.foo
class Derived_B(Base):
meth = Base.bar
Derived_A().meth()
Derived_B().meth()
This works, but I don't like verbatim references to Base in derived classes. Is there a way to use super or alike for this?
You can't do that.
class keyword in Python is used to create classes which are instances of type type. In it's simplified version, it does the following:
Python creates a namespace and executes the body of the class in that namespace so that it will be populated with all methods and attributes and so on...
Then calls the three-arguments form of type(). The result of this call is your class which is then assign to a symbol which is the name of your class.
The point is when the body of the class is being executed. It doesn't know about the "bases". Those bases are passed to the type() after that.
I also explained the reasons why you can't use super() here.
Does this work for you?
class Base:
def foo(self):
print('foo')
def bar(self):
print('bar')
class Derived_A(Base):
def __init__(self):
self.meth = super().foo
class Derived_B(Base):
def __init__(self):
self.meth = super().bar
a = Derived_A().meth()
b = Derived_B().meth()
You'll need to lookup the method on the base class after the new type is created. In the body of the class definition, the type and base classes are not accessible.
Something like:
class Derived_A(Base):
def meth(self):
return super().foo()
Now, it is possible to do some magic behind the scenes to expose Base to the scope of the class definition as its being executed, but that's much dirtier, and would mean that you'd need to supply a metaclass in your class definition.
Since you want "magic", there is still one sane option we can take before diving into metaclasses. Requires Python 3.9+
def alias(name):
def inner(cls):
return getattr(cls, name).__get__(cls)
return classmethod(property(inner))
class Base:
def foo(self):
...
class Derived_A(Base):
meth = alias("foo")
Derived_A().meth() # works
Derived_A.meth() # also works
Yes, this does require passing the method name as a string, which destroys your IDE and typechecker's ability to reason about it. But there isn't a good way to get what you are wanting without some compromises like that.
Really, a bit of redundancy for readability is probably worth it here.
For a recursive function we can do:
def f(i):
if i<0: return
print i
f(i-1)
f(10)
However is there a way to do the following thing?
class A:
# do something
some_func(A)
# ...
If I understand your question correctly, you should be able to reference class A within class A by putting the type annotation in quotes. This is called forward reference.
class A:
# do something
def some_func(self, a: 'A')
# ...
See ref below
https://github.com/python/mypy/issues/3661
https://www.youtube.com/watch?v=AJsrxBkV3kc
In Python you cannot reference the class in the class body, although in languages like Ruby you can do it.
In Python instead you can use a class decorator but that will be called once the class has initialized. Another way could be to use metaclass but it depends on what you are trying to achieve.
You can't with the specific syntax you're describing due to the time at which they are evaluated. The reason the example function given works is that the call to f(i-1) within the function body is because the name resolution of f is not performed until the function is actually called. At this point f exists within the scope of execution since the function has already been evaluated. In the case of the class example, the reference to the class name is looked up during while the class definition is still being evaluated. As such, it does not yet exist in the local scope.
Alternatively, the desired behavior can be accomplished using a metaclass like such:
class MetaA(type):
def __init__(cls):
some_func(cls)
class A(object):
__metaclass__=MetaA
# do something
# ...
Using this approach you can perform arbitrary operations on the class object at the time that the class is evaluated.
Maybe you could try calling __class__.
Right now I'm writing a code that calls a class method from within the same class.
It is working well so far.
I'm creating the class methods using something like:
#classmethod
def my_class_method(cls):
return None
And calling then by using:
x = __class__.my_class_method()
It seems most of the answers here are outdated. From python3.7:
from __future__ import annotations
Example:
$ cat rec.py
from __future__ import annotations
class MyList:
def __init__(self,e):
self.data = [e]
def add(self, e):
self.data.append(e)
return self
def score(self, other:MyList):
return len([e
for e in self.data
if e in other.data])
print(MyList(8).add(3).add(4).score(MyList(4).add(9).add(3)))
$ python3.7 rec.py
2
Nope. It works in a function because the function contents are executed at call-time. But the class contents are executed at define-time, at which point the class doesn't exist yet.
It's not normally a problem because you can hack further members into the class after defining it, so you can split up a class definition into multiple parts:
class A(object):
spam= 1
some_func(A)
A.eggs= 2
def _A_scramble(self):
self.spam=self.eggs= 0
A.scramble= _A_scramble
It is, however, pretty unusual to want to call a function on the class in the middle of its own definition. It's not clear what you're trying to do, but chances are you'd be better off with decorators (or the relatively new class decorators).
There isn't a way to do that within the class scope, not unless A was defined to be something else first (and then some_func(A) will do something entirely different from what you expect)
Unless you're doing some sort of stack inspection to add bits to the class, it seems odd why you'd want to do that. Why not just:
class A:
# do something
pass
some_func(A)
That is, run some_func on A after it's been made. Alternately, you could use a class decorator (syntax for it was added in 2.6) or metaclass if you wanted to modify class A somehow. Could you clarify your use case?
If you want to do just a little hacky thing do
class A(object):
...
some_func(A)
If you want to do something more sophisticated you can use a metaclass. A metaclass is responsible for manipulating the class object before it gets fully created. A template would be:
class AType(type):
def __new__(meta, name, bases, dct):
cls = super(AType, meta).__new__(meta, name, bases, dct)
some_func(cls)
return cls
class A(object):
__metaclass__ = AType
...
type is the default metaclass. Instances of metaclasses are classes so __new__ returns a modified instance of (in this case) A.
For more on metaclasses, see http://docs.python.org/reference/datamodel.html#customizing-class-creation.
If the goal is to call a function some_func with the class as an argument, one answer is to declare some_func as a class decorator. Note that the class decorator is called after the class is initialized. It will be passed the class that is being decorated as an argument.
def some_func(cls):
# Do something
print(f"The answer is {cls.x}")
return cls # Don't forget to return the class
#some_func
class A:
x = 1
If you want to pass additional arguments to some_func you have to return a function from the decorator:
def some_other_func(prefix, suffix):
def inner(cls):
print(f"{prefix} {cls.__name__} {suffix}")
return cls
return inner
#some_other_func("Hello", " and goodbye!")
class B:
x = 2
Class decorators can be composed, which results in them being called in the reverse order they are declared:
#some_func
#some_other_func("Hello", "and goodbye!")
class C:
x = 42
The result of which is:
# Hello C and goodbye!
# The answer is 42
What do you want to achieve? It's possible to access a class to tweak its definition using a metaclass, but it's not recommended.
Your code sample can be written simply as:
class A(object):
pass
some_func(A)
If you want to refer to the same object, just use 'self':
class A:
def some_func(self):
another_func(self)
If you want to create a new object of the same class, just do it:
class A:
def some_func(self):
foo = A()
If you want to have access to the metaclass class object (most likely not what you want), again, just do it:
class A:
def some_func(self):
another_func(A) # note that it reads A, not A()
Do remember that in Python, type hinting is just for auto-code completion therefore it helps IDE to infer types and warn user before runtime. In runtime, type hints almost never used(except in some cases) so you can do something like this:
from typing import Any, Optional, NewType
LinkListType = NewType("LinkList", object)
class LinkList:
value: Any
_next: LinkListType
def set_next(self, ll: LinkListType):
self._next = ll
if __name__ == '__main__':
r = LinkList()
r.value = 1
r.set_next(ll=LinkList())
print(r.value)
And as you can see IDE successfully infers it's type as LinkList:
Note: Since the next can be None, hinting this in the type would be better, I just didn't want to confuse OP.
class LinkList:
value: Any
next: Optional[LinkListType]
It's ok to reference the name of the class inside its body (like inside method definitions) if it's actually in scope... Which it will be if it's defined at top level. (In other cases probably not, due to Python scoping quirks!).
For on illustration of the scoping gotcha, try to instantiate Foo:
class Foo(object):
class Bar(object):
def __init__(self):
self.baz = Bar.baz
baz = 15
def __init__(self):
self.bar = Foo.Bar()
(It's going to complain about the global name 'Bar' not being defined.)
Also, something tells me you may want to look into class methods: docs on the classmethod function (to be used as a decorator), a relevant SO question. Edit: Ok, so this suggestion may not be appropriate at all... It's just that the first thing I thought about when reading your question was stuff like alternative constructors etc. If something simpler suits your needs, steer clear of #classmethod weirdness. :-)
Most code in the class will be inside method definitions, in which case you can simply use the name A.
So I have some god forsaken legacy code that uses the reserved word property, um wrong. In a base class that gets inherited they have basically implemented.
class TestClass(object):
def __init__(self, property):
self._property = property
#property
def property(self):
return self._property
test = TestClass('test property')
print(test.property)
Which runs without error. If you add another method below that you get,
class TestClass2(object):
def __init__(self, property):
self._property = property
#property
def property(self):
return self._property
#property
def other_property(self):
return 'test other property'
test = TestClass2('test property')
print(test.property)
print(test.other_property)
Which throws:
---> 10 #property
11 def other_property(self):
12 print('test other property')
TypeError: 'property' object is not callable
Because you know you have overwritten property in the local namespace.
class TestClass3(object):
def __init__(self, property):
self._property = property
#property
def other_property(self):
return 'test other property'
#property
def property(self):
return self._property
test = TestClass3('test property')
print(test.property)
print(test.other_property)
You can work around this if you always define your property overwrite at the bottom of your class. If the property method is only defined on the base class you inherit from things also work out, because namespaces.
class TestClass4(TestClass):
def __init__(self, property):
super(TestClass4, self).__init__(property)
#property
def other_property(self):
return 'test other property'
test = TestClass4('test property')
print(test.property)
print(test.other_property)
My righteous indignation says that we MUST update this variable name in the huge amount of legacy code, because GAAAAH, but other than having to remember to add new methods above the definition of property definition in the rarely modified base class, this doesn't actually break anything right?
dont shadow builtins... with almost no refactoring at all you can avoid shadowing the builtin entirely
use __getattr__ instead of #property to return your _property member ...
class TestClass(object):
def __init__(self):
self._property = 12
def __getattr__(self,item):
if item == "property":
#do your original getter code for `property` here ...
# now you have not overwritten the property keyword at all
return getattr(self,"_property") # just return the variable
class TestClass2(TestClass):
def __init__(self):
self._property = 67
print TestClass2().property
class MySubClass(TestClass):
#property
def a_property(self):
return 5
print MySubClass().property
print MySubClass().a_property
really, as an aside, theres not any good reason imho to use #property in python. all it does is end up confusing other programmers later and obscuring the fact that you are actually calling a function. I used to do it regularly ... I now avoid it unless I have a very very compelling reason not to
Yes, if you always add new methods above the definition of the property method nothing will break. So put a nice big comment to that effect in the code. Hopefully, anyone wanting to override property in a derived class will look at the base class first and see your comment...
BTW, the property arg to the __init__ method also shadows property, but I guess that's not an issue.
Ideally, someone should clean this mess up, but I understand that it may not be cost-effective to do that.
Also, I'm somewhat baffled why the original coder made property an #property in the first place. That construct should only be used when the value of the attribute has to be calculated dynamically, not for simply returning a static attribute. Perhaps they were new to Python and they were told that's the way to do getters in Python...
You could always remap property to another name. So long as you choose a name that doesn't match your other class attributes, and it won't be exposed in the external interface for the class, so it doesn't really matter what you name it.
tproperty = property
class Test(...)
#tproperty
def property(self):
....
We can rename class methods at class definition time with a metaclass. This question is not about that.
This is more of a thought experiment, so humour me a little please.
Say I wanted to write two decorators that are used like this:
class SomeClass(object):
#append_A
def some_method( self ):
pass
#append_B
def some_method( self ):
pass
Which would result in SomeClass having two methods: some_method_A and some_method_B
Is this possible and if so, can you point me in the right direction?
I've tried changing the frame's f_locals a few different ways, but the method name still persists.
No, it's not possible to change method names using decorator, as explained in the documentation:
The decorator syntax is merely syntactic sugar, the following two function definitions are semantically equivalent:
def f(...):
...
f = staticmethod(f)
#staticmethod
def f(...):
...
More syntax discussion goes here.
Update
I guess we could do something like leave the method alone in the decorator but also add a new method with an edited name in the scope it was defined (this case the class). The main thing is defining two methods with the same name then ending up with two differently named methods which are passed to the metaclass.
For this purpose you can use the class decorator:
def append_B(func):
func.suffix='_B'
return func
def appendable(class_obj):
for name in dir(class_obj):
if not name.startswith('_'):
attr = class_obj.__dict__[name] #getattr(class_obj, name)
suffix = getattr(attr, 'suffix', None)
if isinstance(suffix,str):
attr.suffix = None
setattr(class_obj,name+suffix, getattr(class_obj, name))
#delattr(class_obj,name)
return class_obj
The following usage allows you to define two names for the same method:
#appendable
class B(object):
#append_B
def some_method(s):
print 'B.some_method'
b=B()
b.some_method()
b.some_method_B()
In Python, how do I get a reference to the current class object within a class statement? Example:
def setup_class_members(cls, prefix):
setattr(cls, prefix+"_var1", "hello")
setattr(cls, prefix+"_var2", "goodbye")
class myclass(object):
setup_class_members(cls, "coffee") # How to get "cls"?
def mytest(self):
print(self.coffee_var1)
print(self.coffee_var2)
x = myclass()
x.mytest()
>>> hello
>>> goodbye
Alternatives that I've written off are:
Use locals(): This gives a dict in a class statement that can be written to. This seems to work for classes, however the documentation tells you not to do this. (I might be tempted to go with this alternative if someone can assure me that this will continue to work for some time.)
Add members to the class object after the class statement: My actual application is to derive a PyQt4 QWidget class with dynamically created pyqtProperty class attributes. QWidget is unusual in that it has a custom metaclass. Very roughly, the metaclass compiles a list of pyqtProperties and stores it as additional member. For this reason, properties that are added to the class after creation have no effect. An example to clear this up:
from PyQt4 import QtCore, QtGui
# works
class MyWidget1(QtGui.QWidget):
myproperty = QtCore.pyqtProperty(int)
# doesn't work because QWidget's metaclass doesn't get to "compile" myproperty
class MyWidget2(QtGui.QWidget):
pass
MyWidget2.myproperty = QtCore.pyqtProperty(int)
Please note that the above will work for most programming cases; my case just happens to be one of those unusual corner cases.
For Python 3, the class must be declared as
class myclass(object, metaclass = Meta):
prefix = "coffee"
...
A few other points:
The metaclass may be a callable, not just a class (Python 2&3)
If the base class of your class already has a non-standard metaclass, you have to make sure you call it's __init__() and __new__() methods instead of type's.
The class statement accepts keyword parameters that are passed on to the metaclass (Python 3 only)
A rewrite of mouad's solution in Python 3 using all of the above is...
def MetaFun(name, bases, attr, prefix=None):
if prefix:
attr[prefix+"_var1"] = "hello"
attr[prefix+"_var2"] = "goodbye"
return object.__class__(name, bases, attr)
class myclass(object, metaclass = MetaFun, prefix="coffee"):
def mytest(self):
print(self.coffee_var1)
print(self.coffee_var2)
AFAIK there is two way to do what you want:
Using metaclass, this will create your two variables in class creation time (which i think is what you want):
class Meta(type):
def __new__(mcs, name, bases, attr):
prefix = attr.get("prefix")
if prefix:
attr[prefix+"_var1"] = "hello"
attr[prefix+"_var2"] = "goodbye"
return type.__new__(mcs, name, bases, attr)
class myclass(object):
__metaclass__ = Meta
prefix = "coffee"
def mytest(self):
print(self.coffee_var1)
print(self.coffee_var2)
Create your two class variable in instantiation time:
class myclass(object):
prefix = "coffee"
def __init__(self):
setattr(self.__class__, self.prefix+"_var1", "hello")
setattr(self.__class__, self.prefix+"_var2", "goodbye")
def mytest(self):
print(self.coffee_var1)
print(self.coffee_var2)
N.B: I'm not sure what you want to achieve because if you want to create dynamic variables depending on the prefix variable why are you accessing like you do in your mytest method ?! i hope it was just an example.
Two more approaches you might use:
A class decorator.
def setup_class_members(prefix):
def decorator(cls):
setattr(cls, prefix+"_var1", "hello")
setattr(cls, prefix+"_var2", "goodbye")
return cls
return decorator
#setup_class_members("coffee")
class myclass(object):
# ... etc
Especially if you need to add attributes in various combinations, the decorator approach is nice because it does not have any effect on inheritance.
If you are dealing with a small set of of attributes that you wish to combine in various ways, you can use mixin classes. A mixin class is a regular class, it's just intended to "mix in" various attributes to some other class.
class coffee_mixin(object):
coffee_var1 = "hello"
coffee_var2 = "goodbye"
class tea_mixin(object):
tea_var1 = "good morning old bean"
tea_var2 = "pip pip cheerio"
class myclass(coffee_mixin, tea_mixin):
# ... etc
See zope.interface.declarations._implements for an example of doing this kind of magic. Just be warned that it's a serious maintainability and portability risk.