python - ágil - usando django




Acessando o endereço da memória do objeto (6)

Quando você chama o método object.__repr__() do object.__repr__() em Python, você obtém algo assim:

<__main__.Test object at 0x2aba1c0cf890> 

Existe alguma maneira de obter um endereço de memória se você sobrecarregar __repr__() , outro chamando super(Class, obj).__repr__() e regexing-lo?


Apenas em resposta ao Torsten, não consegui chamar addressof() em um objeto python regular. Além disso, id(a) != addressof(a) . Isso é no CPython, não sei sobre mais nada.

>>> from ctypes import c_int, addressof
>>> a = 69
>>> addressof(a)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: invalid type
>>> b = c_int(69)
>>> addressof(b)
4300673472
>>> id(b)
4300673392

Apenas use

id(object)

Embora seja verdade que id(object) obtém o endereço do objeto na implementação padrão do CPython, isso geralmente é inútil ... você não pode fazer nada com o endereço do código puro do Python.

A única vez que você seria realmente capaz de usar o endereço é de uma biblioteca de extensão C ... caso em que é trivial para obter o endereço do objeto desde objetos Python são sempre passados ​​como ponteiros C.


Existem alguns problemas aqui que não são abordados por nenhuma das outras respostas.

Primeiro, id só retorna:

a “identidade” de um objeto. Este é um inteiro (ou inteiro longo) que é garantido para ser exclusivo e constante para este objeto durante sua vida útil. Dois objetos com tempos de vida não sobrepostos podem ter o mesmo valor id() .

No CPython, este é o ponteiro para o PyObject que representa o objeto no interpretador, que é a mesma coisa que o object.__repr__ exibe. Mas isso é apenas um detalhe de implementação do CPython, e não algo que é verdade no Python em geral. O Jython não lida com ponteiros, lida com referências Java (que a JVM provavelmente representa como ponteiros, mas você não pode vê-las - e não gostaria, porque o GC pode movê-las). PyPy permite que diferentes tipos possuam diferentes tipos de id , mas o mais geral é apenas um índice em uma tabela de objetos para os quais você chamou id , o que obviamente não será um ponteiro. Não tenho certeza sobre o IronPython, mas suspeito que seja mais parecido com o Jython do que com o CPython nesse aspecto. Assim, na maioria das implementações em Python, não há como obter o que quer que seja exibido nesse repr , e não adianta se você o fizer.

Mas e se você se importa apenas com o CPython? Esse é um caso bem comum, afinal.

Bem, primeiro, você pode notar que id é um número inteiro; * se você quiser que 0x2aba1c0cf890 string em vez do número 46978822895760 , você terá que formatá-lo sozinho. Nos object.__repr__ , acredito que o object.__repr__ está usando o formato %p printf , que você não tem no Python… mas você sempre pode fazer isso:

format(id(spam), '#010x' if sys.maxsize.bit_length() <= 32 else '#18x')

* No 3.x, é um int . Em 2.x, é um int se for grande o suficiente para segurar um ponteiro - o que pode não ser devido a problemas numéricos assinados em algumas plataformas - e um long caso contrário.

Existe alguma coisa que você pode fazer com esses ponteiros além de imprimi-los? Claro (novamente, assumindo que você só se importa com o CPython).

Todas as funções da API C levam um ponteiro para um PyObject ou um tipo relacionado. Para esses tipos relacionados, você pode simplesmente chamar PyFoo_Check para ter certeza de que é realmente um objeto Foo , então lançar com (PyFoo *)p . Então, se você está escrevendo uma extensão C, o id é exatamente o que você precisa.

E se você estiver escrevendo código puro em Python? Você pode chamar exatamente as mesmas funções com pythonapi de ctypes .

Finalmente, algumas das outras respostas trouxeram ctypes.addressof . Isso não é relevante aqui. Isso só funciona para objetos ctypes como c_int32 (e talvez alguns objetos semelhantes a buffer de memória, como aqueles fornecidos por numpy ). E, mesmo lá, não está lhe dando o endereço do valor c_int32 , está lhe dando o endereço do nível c_int32 int32 que o c_int32 encerra.

Dito isto, muitas vezes, se você realmente acha que precisa do endereço de algo, você não queria um objeto nativo do Python, você queria um objeto ctypes .


Você pode obter algo adequado para esse fim com:

id(self)

Você poderia reimplementar a repr default neste caminho:

def __repr__(self):
    return '<%s.%s object at %s>' % (
        self.__class__.__module__,
        self.__class__.__name__,
        hex(id(self))
    )




repr